package gov.pbc.nn.kjgl.maintenance.view;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.bstek.bdf2.core.business.IUser;
import com.bstek.bdf2.core.context.ContextHolder;
import com.bstek.bdf2.core.orm.hibernate.ISessionCallback;
import com.bstek.bdf2.core.service.IDeptService;
import com.bstek.dorado.annotation.DataProvider;
import com.bstek.dorado.annotation.DataResolver;
import com.bstek.dorado.annotation.Expose;
import com.bstek.dorado.core.Configure;
import com.bstek.dorado.data.entity.EntityState;
import com.bstek.dorado.data.entity.EntityUtils;
import com.bstek.dorado.data.provider.Criteria;
import com.bstek.dorado.data.provider.Page;
import com.bstek.dorado.data.variant.Record;
import com.bstek.dorado.uploader.DownloadFile;
import com.bstek.dorado.uploader.UploadFile;
import com.bstek.dorado.uploader.annotation.FileProvider;
import com.bstek.dorado.uploader.annotation.FileResolver;

import gov.pbc.nn.core.bdf.entity.Dept;
import gov.pbc.nn.core.bdf.service.DeptService;
import gov.pbc.nn.core.dao.CommonHibernateDao;
import gov.pbc.nn.core.dao.CommonJdbcDao;
import gov.pbc.nn.core.utils.SecurityUtils;
import gov.pbc.nn.kjgl.Constants;
import gov.pbc.nn.kjgl.maintenance.entity.SysEntity;
import gov.pbc.nn.kjgl.maintenance.entity.SysInvolveDept;
import gov.pbc.nn.kjgl.maintenance.entity.SysMaterial;
import gov.pbc.nn.uflo.UfloUtils;
import gov.pbc.nn.uflo.entity.Opinion;

/**
 * 系统维护
 * 
 * @author Administrator
 * 
 */
@Component
public class SysMaintainPR {

	@Resource(name = CommonHibernateDao.BEAN_ID)
	private CommonHibernateDao hibernateDao;

	@Resource(name = CommonJdbcDao.BEAN_ID)
	private CommonJdbcDao jdbcDao;
	
	@Autowired
	@Qualifier(IDeptService.BEAN_ID)
	private IDeptService deptService;

	@DataProvider
	public void loadSys(final Page<SysEntity> page, Criteria criteria) {
		/*final String sql = "SELECT\n" + "	e.*\n" + "FROM\n" + "	(\n" + "		SELECT\n"
				+ "			s.*, u.ID_ AS uid,\n" + "			u.USERNAME_ AS staff\n" + "		FROM\n"
				+ "			t_sys_entity s\n" + "		LEFT JOIN t_sys_operation_staff u ON s.ID_ = u.SYS_ID_\n"
				+ "		AND s.INVALID_ = 0\n" + "		AND u.INVALID_ = 0\n" + "	) e\n" + "WHERE\n" + "	(\n"
				+ "		CASE\n" + "		WHEN e.uid IS NULL THEN\n" + "			e.create_user_\n"
				+ "		WHEN e.uid IS NOT NULL THEN\n" + "			e.staff\n" + "		END\n" + "	) =:username\n"
				+ "ORDER BY\n" + "	e.AUDIT_STATE_";
		final String countSql = "select count(*) from (" + sql + ") t";
		this.hibernateDao.doInHibernateSession(new ISessionCallback<Void>() {

			@Override
			public Void doInSession(Session session) {
				SQLQuery query = session.createSQLQuery(sql);
				query.addEntity("e", SysEntity.class);
				query.setString("username", ContextHolder.getLoginUserName());
				query.setMaxResults(page.getPageSize());
				query.setFirstResult((page.getPageNo() - 1) * page.getPageSize());
				page.setEntities(query.list());
				query = session.createSQLQuery(countSql);
				query.setString("username", ContextHolder.getLoginUserName());
				Number n = (Number) query.uniqueResult();
				page.setEntityCount(n.intValue());
				return null;
			}

		});
		*/
		
		DetachedCriteria dc = this.hibernateDao.buildDetachedCriteria(criteria, SysEntity.class);
		dc.add(Restrictions.eq("invalid", false));
		dc.add(Restrictions.eq("auditState", 2));
		Dept dept = (Dept) ContextHolder.getLoginUser().getDepts().get(0);
		Dept zzDept = (Dept) SecurityUtils.getZZByDept(dept);
		if (!Dept.NANNING.equals(zzDept.getId())) {
		dc.add(Restrictions.or(Restrictions.eq("deptId", dept.getId()), Restrictions.eq("operationDeptId", dept.getId())));
		}
		this.hibernateDao.pagingQuery(page, dc);
	}

	@DataProvider
	public List<SysInvolveDept> loadInvolveDept(String sysId) {
		DetachedCriteria dc = DetachedCriteria.forClass(SysInvolveDept.class);
		dc.add(Restrictions.eq("invalid", false));
		dc.add(Restrictions.eq("sysId", sysId));
		return (List<SysInvolveDept>) this.hibernateDao.query(dc);
	}

	@DataResolver
	@Transactional
	public void save(SysEntity sys) {
		EntityState state = EntityUtils.getState(sys);
		if (state == EntityState.NEW) {
			this.hibernateDao.save(sys);
			List<SysInvolveDept> depts = EntityUtils.getValue(sys, "depts");
			this.saveSysInvolveDepts(sys, depts);
			this.saveSysMaterial(sys, (List<SysMaterial>) EntityUtils.getValue(sys, "materials"));
		} else {
			if (state == EntityState.MODIFIED) {
				this.hibernateDao.update(sys);
				List<SysInvolveDept> depts = EntityUtils.getValue(sys, "depts");
				this.saveSysInvolveDepts(sys, depts);
				this.saveSysMaterial(sys, (List<SysMaterial>) EntityUtils.getValue(sys, "materials"));
			} else if (state == EntityState.NONE) {
				List<SysInvolveDept> depts = EntityUtils.getValue(sys, "depts");
				this.saveSysInvolveDepts(sys, depts);
				this.saveSysMaterial(sys, (List<SysMaterial>) EntityUtils.getValue(sys, "materials"));
			}
		}
	}

	private void saveSysInvolveDepts(SysEntity sys, List<SysInvolveDept> depts) {
		if (depts != null) {
			for (SysInvolveDept dept : depts) {
				EntityState state = EntityUtils.getState(dept);
				if (state == EntityState.NEW) {
					dept.setSysId(sys.getId());
					dept.setSysName(sys.getName());
					this.hibernateDao.save(dept);
				} else if (state == EntityState.MODIFIED) {
					this.hibernateDao.update(dept);
				} else if (state == EntityState.DELETED) {
					this.hibernateDao.delete(dept);
				}
			}
		}
	}

	private void saveSysMaterial(SysEntity sys, List<SysMaterial> smList) {
		if (smList != null) {
			for (SysMaterial sm : smList) {
				EntityState state = EntityUtils.getState(sm);
				if (state == EntityState.NEW) {
					sm.setSysId(sys.getId());
					sm.setSysName(sys.getName());
					this.hibernateDao.save(sm);
				} else if (state == EntityState.MODIFIED) {
					this.hibernateDao.update(sm);
				} else if (state == EntityState.DELETED) {
					this.hibernateDao.delete(sm);
				}
			}
		}
	}

	@DataProvider
	public List<Opinion> loadOpinion(String sysId) {
		return UfloUtils.getOpinions(null, sysId, null, null, null);
	}

	@DataProvider
	public List<SysMaterial> loadMaterial(String sysId) {
		DetachedCriteria dc = DetachedCriteria.forClass(SysMaterial.class);
		dc.add(Restrictions.eq("invalid", false));
		dc.add(Restrictions.eq("sysId", sysId));
		dc.add(Restrictions.eq("type", 100));
		return (List<SysMaterial>) this.hibernateDao.query(dc);
	}

	@FileResolver
	@Transactional
	public SysMaterial uploadFile(UploadFile file, Map<String, Object> params) throws IOException {
		String sysId = (String) params.get("sysId");
		String sysName = (String) params.get("sysName");
		SysMaterial sm = new SysMaterial();
		sm.setType(100);
		sm.setFileName(file.getFileName());
		Path target = Paths.get(Configure.getString("SYS_YUNWEI_FILE_UPLOAD_PATH"));
		if (!Files.isDirectory(target)) {
			Files.createDirectories(target);
		}
		target = target.resolve(UUID.randomUUID().toString());
		sm.setPath(target.toString());
		if (StringUtils.isEmpty(sysId)) {
		} else {
			sm.setSysId(sysId);
			sm.setSysName(sysName);
			this.hibernateDao.save(sm);
		}
		Files.copy(file.getInputStream(), target);
		return sm;
	}

	@FileProvider
	public DownloadFile downloadFile(Map<String, Object> params) throws FileNotFoundException {
		String fileName = (String) params.get("fileName");
		String path = (String) params.get("path");
		DownloadFile df = new DownloadFile(fileName, new FileInputStream(path));
		return df;
	}

	@Expose
	@Transactional
	public void deleteMaterial(String id) {
		this.hibernateDao.delete(id, SysMaterial.class);
	}
	
	@Expose
	public String checkDept(List<Record> depts) throws Exception {
		for (Record dept : depts) {
			Dept loginDept = (Dept) ContextHolder.getLoginUser().getDepts().get(0);
			Dept loginZZDept = (Dept) SecurityUtils.getZZByDept(loginDept);
			if (StringUtils.isNotBlank(dept.getString("deptLevel"))) {
				return "【"+dept.getString("name") + "】不属于部门,请重新选择!";
			} else if (dept.getString("id").startsWith(loginZZDept.getId()) == false) {
				return "【"+dept.getString("name") + "】不属于您所在的中支,请重新选择!";
			}
		}
		return null;
	}
}
